<H2>SharpPcap tutorial: a step by step guide to using SharpPcap</H2>
<P>The text of this tutorial is taken directly from WinPcap's <A href="http://www.winpcap.org/docs/docs31/html/group__wpcap__tut.html">
		official tutorial </A>but is modified to show the C# use of the SharpPcap 
	library. All examples can be downloaded together with SharpPcap source code 
	from <A href="http://sharppcap.sourceforge.net">SharpPcap</A>
	's homepage.</P>
<P>For use on windows the WinPcap library must be installed before attempting to run any 
	of these examples, so please download and install the latest version from <A href="http://www.winpcap.org/install/default.htm">
		WinPcap's download page</A>.</P>
<P> For use on Linux the pcap library must be installed.</P>
<P>SharpPcap was written and tested using .NET v1.1 and Windows 2000/XP and Mono 1.9.1 on Ubuntu 8.10.
If you try it on another platform and have difficulties please submit a bug on the project webpage.
<P>The following topics are covered in this tutorial:</P>
<ol>
	<li>
		<a href="#ifList">Obtaining the device list</a>
	<li>
		<a href="#basicCap">Opening an adapter and capturing packets</a>
	<li>
		<a href="#basicCapNoCallback">Capturing packets without the event handler</a>
	<li>
		<a href="#filter">Filtering the traffic</a>
	<li>
		<a href="#dumpTCP">Interpreting the packets</a>
	<li>
		<a href="#offline">Handling offline dump files</a>
	<li>
		<a href="#sendPackets">Sending Packets</a>
	<li>
		<a href="#statistics">Gathering Statistics on the network traffic</a></li>
</ol>
<H3 id="ifList">1. Obtaining the device list
</H3>
<P>Typically, the first thing that a Pcap-based application does is get a list 
	of attached network adapters. SharpPcap provide the <CODE>GetAllDevices()</CODE>
	function for this purpose: this function returns a list of <CODE>PcapDevice</CODE>
	objects, each of which contains comprehensive information about an attached 
	adapter. In particular, the fields <CODE>PcapName</CODE> and <CODE>PcapDescription</CODE>
	contain the name and a human readable description, respectively, of the 
	corresponding device. The following C# sample shows how to retrieve a list of 
	adapters and print it on the screen, printing an error if no adapters are 
	found.
</P>
<PRE>/* Retrieve the device list */
List<PcapDevice> devices = SharpPcap.Pcap.GetAllDevices();

/*If no device exists, print error */
if(devices.Count&lt;1)
{
    Console.WriteLine("No device found on this machine");
    return;
}

int i=0;

/* Scan the list printing every entry */
foreach(PcapDevice dev in devices)
{
    Console.Writeline("{0}", dev.ToString());
    Console.WriteLine();
    i++;
}</PRE>
<P>The output of the above application will be as something like:</P>
<PRE>SharpPcap 1.0.2.0, Example4.IfList.cs

The following devices are available on this machine:
----------------------------------------------------

0) Generic dialup adapter

        Name:   \Device\NPF_GenericDialupAdapter
        IP Address:             0.0.0.0
        Loopback:               False

1) Intel(R) PRO/1000 MT Mobile Connection (Microsoft's Packet Scheduler)

        Name:   \Device\NPF_{355BF264-B768-454A-84BC-096A44F0ADA9}
        IP Address:             10.10.10.100
        Loopback:               False

Hit 'Enter' to exit...</PRE>
<H3 id="basicCap">2. Opening an adapter and capturing packets</H3>
<P>Now that we've seen how to obtain an adapter to play with, let's start the real 
	job, opening an adapter and capturing some traffic. In this section we'll write 
	a program that prints some information about each packet flowing through the 
	adapter.
</P>
<P>The function that opens a device for capture is <CODE>PcapOpen()</CODE> which is 
	overloaded with some arguments as follows:
</P>
<UL>
	<LI>
		<CODE>PcapOpen()</CODE>
	<LI>
		<CODE>PcapOpen(bool promiscuous_mode)</CODE>
	<LI>
		<CODE>PcapOpen(bool promiscuous_mode, int read_timeout)</CODE>
	</LI>
</UL>
<P>The above two arguments deserve some further explanation:</P>
<P><CODE><I>promiscuous_mode</I>:</CODE> In normal operation, an adapter only 
	captures packets from the network that are destined to it; the packets 
	exchanged by other hosts are therefore ignored. Instead, when the adapter is in 
	promiscuous mode it captures all packets whether they are destined to it or 
	not. This means that on shared media (like non-switched Ethernet), WinPcap will 
	be able to capture the packets of other hosts. Promiscuous mode is the default 
	for most capture applications, so we enable it in the following example.
</P>
<P><CODE><I>read_timeout</I>: </CODE>specifies the read timeout, in milliseconds. A 
	read on the adapter (for example, using the <CODE>PcapGetNextPacket()</CODE> function) 
	will always return after <CODE>read_timeout</CODE> milliseconds, even if no 
	packets are available from the network. <CODE>read_timeout</CODE> also defines 
	the interval between statistical reports if the adapter is in statistical mode 
	(see the <I>Gathering Statistics on the network traffic</I> section). Setting <CODE>
		read_timeout</CODE> to 0 means no timeout, a read on the adapter never 
	returns if no packets arrive. A -1 timeout on the other side causes a read on 
	the adapter to always return immediately.</P>
<P>The following example shows the use of the <CODE>PcapOnPacketArrival</CODE> event 
	for receiving packets. We create an event handler that is being called whenever 
	a new packet is going through the <CODE>PcapDevice</CODE>:</P>
<PRE>//Extract a device from the list
PcapDevice device = devices[i];

//Register our handler function to the 'packet arrival' event
device.PcapOnPacketArrival += 
    new SharpPcap.PacketArrivalEvent( device_PcapOnPacketArrival );

//Open the device for capturing
//true -- means promiscuous mode
//1000 -- means a read wait of 1000ms
device.PcapOpen(true, 1000);

Console.WriteLine("-- Listenning on {0}, hit 'Enter' to stop...",
    device.PcapDescription);

//Start the capturing process
device.PcapStartCapture();

//Wait for 'Enter' from the user.
Console.ReadLine();

//Stop the capturing process
device.PcapStopCapture();

//Close the pcap device
device.PcapClose();</PRE>
<P>And here is our packet handler implementation:
</P>
<PRE>/// &lt;SUMMARY&gt;
/// Prints the time and length of each received packet
/// &lt;/SUMMARY&gt;
private static void device_PcapOnPacketArrival(object sender, Packet packet)
{
    DateTime time = packet.PcapHeader.Date;
    int len = packet.PcapHeader.PacketLength;
    Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 
        time.Hour, time.Minute, time.Second, time.Millisecond, len);
}</PRE>
<P>Once the adapter is opened, the capture can be started with the <CODE>PcapStartCapture()</CODE>
	or <CODE>PcapCapture(int packetCount)</CODE> functions. These two functions are 
	very similar, the difference is that <CODE>PcapStartCapture()</CODE> is a 
	non-blocking function that starts the capturing process on a new thread, while <CODE>
		PcapCapture(int packetCount) </CODE>blocks until <CODE>packetCount </CODE>packets 
	have been captured. When using <CODE>PcapStartCapture()</CODE> we should later 
	call <CODE>PcapStopCapture()</CODE> to terminate the capture process. When 
	using <CODE>PcapCapture(int packetCount)</CODE> it is possible to pass a <CODE>SharpPcap.INFINITE</CODE>
	value to keep capturing forever.
</P>
<P>Both of these functions require that an event handler for processing packets is 
	registered prior to calling them. This event handler is invoked by <CODE>PcapDevice</CODE>
	for every new packet coming from the network and receives the sender object 
	that invoked this handler (i.e. the <CODE>PcapDevice</CODE> object) and the 
	actual received <CODE>Packet</CODE>, including all the protocol headers. Note 
	that the frame CRC is normally not present in the packet, because it is removed 
	by the network adapter after frame validation. Note also that most adapters 
	discard packets with wrong CRCs, so WinPcap (and therefore SharpPcap) is 
	normally not able to capture them.
</P>
<P>The <CODE>Packet</CODE> class represents a generic packet captured from the 
	network. Each such packet has a <CODE>PcapHeader</CODE> property containing 
	some info (e.g. the timestamp of the capture and the length of the packet) 
	about the captured packet. The above example extracts the timestamp and the 
	length from every <CODE>Packet</CODE> object and prints them on the screen.<BR>
</P>
<P>Please note that there may be a drawback using an event handler for processing 
	packets, mainly related to the fact that the handler is called by the <CODE>PcapDevice</CODE>; 
	therefore the user application does not have direct control over it. Another 
	approach (and to have more readable programs) is to use the <CODE>PcapGetNextPacket()</CODE>
	function, which is presented in the next section.
</P>
<H3 id="basicCapNoCallback">3. Capturing packets without the event handler
</H3>
<P>The example program in this section behaves exactly like the previous sample, 
	but it uses <CODE>PcapGetNextPacket()</CODE> instead of registering an event 
	handler. The <CODE>PcapOnPacketArrival</CODE> event is a good practice and 
	could be a good choice in some situations. However, handling a callback is 
	sometimes not practical -- it often makes the program more complex especially 
	in situations with multithreaded applications. In these cases, <CODE>PcapGetNextPacket()</CODE>
	retrievs a packet with a direct call -- using <CODE>PcapGetNextPacket()</CODE>, 
	packets are received only when the programmer wants them. In the following 
	program, we re-use the event handler code of the previous example and move it 
	into a loop in the main function right after the call to <CODE>PcapGetNextPacket()</CODE>.
</P>
<P>Note: the following example will exit if the timeout of 1000ms will expire with 
	no packets on the network.
	<PRE>//Extract a device from the list
PcapDevice device = devices[i];

//Open the device for capturing
//true -- means promiscuous mode
//1000 -- means a read wait of 1000ms
device.PcapOpen(true, 1000);

Console.WriteLine();
Console.WriteLine("-- Listenning on {0}...",
    device.PcapDescription);

Packet packet = null;

//Keep capture packets using PcapGetNextPacket()
while( (packet=device.PcapGetNextPacket()) != null )
{
    // Prints the time and length of each received packet
    DateTime time = packet.PcapHeader.Date;
    int len = packet.PcapHeader.PacketLength;
    Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 
        time.Hour, time.Minute, time.Second, time.Millisecond, len);
}
//Close the pcap device
device.PcapClose();
Console.WriteLine("-- Capture stopped, device closed.");</PRE>
<P></P>
<H3 id="filter">4. Filtering the traffic</H3>
<P>One of the most powerful features offered by libpcap and WinPcap is the 
	filtering engine. It provides a very efficient way to receive subsets of the 
	network traffic, and is (usually) integrated with the capture mechanism 
	provided by WinPcap. The WinPcap lib has an integrated compiler that takes a 
	string containing a high-level Boolean (filter) expression and produces a 
	low-level byte code that can be interpreted by the filter engine of WinPcap's 
	packet driver. The syntax (also known as the <I>tcpdump syntax</I>) of the 
	boolean expression is widely used in many applications other than WinPcap and 
	libpcap. You can find its spec in WinPcap's <A href="http://www.winpcap.org/docs/docs31/html/group__language.html">
		documentation page</A>.
</P>
<P>The function <CODE>PcapSetFilter()</CODE> associates a filter with a capture 
	session in WinPcap's kernel driver. Once <CODE>PcapSetFilter()</CODE> is 
	called, the associated filter will be applied to all the packets coming from 
	the network, and all the conformant packets (i.e., packets for which the 
	boolean expression evaluates to true) will be actually copied to the 
	application. The following code shows how to compile and set a filter.
</P>
<P>Note that WinPcap's expression compiler requires that the netmask of the 
	PcapDevice will be passed together with the filter, because some filters 
	created by the compiler require it. However SharpPcap takes care of it for us 
	by automatically extracting the netmask from the adapter.</P>
<P>The filter expression we use in the following snippet is "ip and tcp", which 
	means to "keep only the packets that are both IPv4 and TCP and deliver them to 
	the application".
</P>
<PRE>//Open the device for capturing
//true -- means promiscuous mode
//1000 -- means a read wait of 1000ms
device.PcapOpen(true, 1000);

//tcpdump filter to capture only TCP/IP packets            
string filter = "ip and tcp";
//Associate the filter with this capture
device.PcapSetFilter( filter );

Console.WriteLine();
Console.WriteLine
    ("-- The following tcpdump filter will be applied: \"{0}\"", 
    filter);
Console.WriteLine
    ("-- Listenning on {0}, hit 'Enter' to stop...",
    device.PcapDescription);

//Start capture packets
device.PcapCapture( SharpPcap.INFINITE );

//Close the pcap device
//(Note: this line will never be called since
// we're capturing infinite number of packets
device.PcapClose();</PRE>
<H3 id="dumpTcp">5. Interpreting the packets</H3>
<P>Now that we are able to capture and filter network traffic, we want to put our 
	knowledge to work with a simple "real world" application. In this lesson we 
	will take the code from the previous sections and use these pieces to build a 
	more useful program. The main purpose of the current program is to show how the 
	protocol headers of a captured packet can be parsed and interpreted. The 
	resulting application, called DumpTCP, prints a summary of the TCP traffic on 
	our network. I have chosen to parse and display the TCP protocol (rather than 
	the UDP example posted in the original tutorial) because it is a bit more 
	interesting than UDP and with SharpPcap it doesn't require too much parsing 
	coding.
</P>
<PRE>/// &lt;SUMMARY&gt;
/// Prints the time, length, src ip, src port, dst ip and dst port
/// for each TCP/IP packet received on the network
/// &lt;/SUMMARY&gt;
private static void device_PcapOnPacketArrival(object sender, Packet packet)
{            
    if(packet is TCPPacket)
    {                
        DateTime time = packet.Timeval.Date;
        int len = packet.PcapHeader.len;

        TCPPacket tcp = (TCPPacket)packet;
        System.Net.IPAddress srcIp = tcp.SourceAddress;
        System.Net.IPAddress dstIp = tcp.DestinationAddress;
        int srcPort = tcp.SourcePort;
        int dstPort = tcp.DestinationPort;

        Console.WriteLine("{0}:{1}:{2},{3} Len={4} {5}:{6} -&gt; {7}:{8}", 
            time.Hour, time.Minute, time.Second, time.Millisecond, len,
            srcIp, srcPort, dstIp, dstPort);
    }
}</PRE>
<P>If you take a look at the <A href="http://www.winpcap.org/docs/docs31/html/group__wpcap__tut6.html">
		UDP example</A> of the original WinPcap tutorial you will see how complex 
	it is to parse the packets (although UDP is a bit simpler to parse than TCP in 
	our example) directly from the raw data bytes provided by the WinPcap library. 
	Lucky for us, SharpPcap provides some useful packet analyzing classes for some 
	common protocols (e.g. TCP, UDP, ICMP and others). All these analyzing classes 
	are a direct C# translation from <A href="http://jpcap.sourceforge.net/">JPcap</A>
	which is a Java wrapper for libpcap/WinPcap similar to SharpPcap. All these 
	analyzing classes can be found under the <CODE>SharpPcap.Packets</CODE> namespace.</P>
<P>As you can see, in our packet handler we first do a check to verify that the <CODE>Packet</CODE>
	object received from the <CODE>PcapDevice</CODE> is of type <CODE>TCPPacet</CODE>, 
	and only then we cast it to a <CODE>TCPPacet</CODE>. This check is not really 
	needed if we set the appropriate filter using the <CODE>PcapSetFilter()</CODE> function, 
	however we use it here as a good practice.
</P>
<P>The <CODE>TCPPacket </CODE>is a subclass of the <CODE>IPPacket </CODE>class 
	(since TCP runs on top of IP), so all TCP/IP fields are accessible using <CODE>TCPPacet</CODE>'s 
	properties. In the above example, we extract the TCP and IP values from the <CODE>TCPPacket</CODE>
	class and print them on the screen (of course the <CODE>TCPPacket</CODE> class 
	contain additional info such as TCP flags and sequence number fields, which are 
	not shown in this example). The result output is something like:</P>
<PRE>Available devices:
------------------

1) Intel(R) PRO/1000 MT Mobile Connection (Microsoft's Packet Scheduler)

-- Please choose a device to capture: 1

-- Listenning on Intel(R) PRO/1000 MT Mobile Connection (Microsoft's Packet Scheduler)...
1:18:17,675 Len=123 66.102.7.147:80 -&gt; 10.21.98.21:43501
1:18:17,675 Len=80 10.21.98.21:43501 -&gt; 66.102.7.147:80
1:18:17,919 Len=54 66.102.7.147:80 -&gt; 10.21.98.21:43501</PRE>
<P>Each of the final 3 lines represents a different packet.</P>
<H3 id="offline">6. Handling offline dump files</H3>
<P>In this section we are going to learn how to handle packet capture to a file 
	(dump to file). WinPcap offers built-in functions for saving network traffic to 
	a file and to read the content of dumps -- this section will teach how to 
	accomplish this with SharpPcap. The format for dump files is the libpcap one. 
	This format contains the data of the captured packets in binary form and is a 
	standard widely used by many network tools including windump, tcpdump, ethereal 
	and snort. Therefore, any dump file we create using SharpPcap can be opened 
	with any of the above tools and others.
</P>
<B>Saving packets to a dump file</B>
<P>First of all, let's see how to write packets in libpcap file format. The 
	following example captures the packets from the selected interface and saves 
	them on a file whose name is provided by the user.
</P>
<PRE>Console.Write("-- Please enter the output file name: ");
string capFile = Console.ReadLine();

PcapDevice device = devices[i];

//Register our handler function to the 'packet arrival' event
device.PcapOnPacketArrival += 
    new SharpPcap.PacketArrivalEvent( device_PcapOnPacketArrival );

//Open the device for capturing
//true -- means promiscuous mode
//1000 -- means a read wait of 1000ms
device.PcapOpen(true, 1000);

//Open or create a capture output file
device.PcapDumpOpen( capFile );

Console.WriteLine();
Console.WriteLine
    ("-- Listenning on {0}, hit 'Ctrl-C' to exit...",
    device.PcapDescription);

//Start capture 'INFINTE' number of packets
device.PcapCapture( SharpPcap.INFINITE );

//Close the pcap device
//(Note: this line will never be called since
// we're capturing infinite number of packets
device.PcapClose();</PRE>
<P>And here is the packet handler that will dump each received packet to the file:</P>
<PRE>/// &lt;SUMMARY&gt;
/// Dumps each received packet to a pcap file
/// &lt;/SUMMARY&gt;
private static void device_PcapOnPacketArrival(object sender, Packet packet)
{                        
    PcapDevice device = (PcapDevice)sender;
    //if device has a dump file opened
    if( device.PcapDumpOpened )
    {
        //dump the packet to the file
        device.PcapDump( packet );
        Console.WriteLine("Packet dumped to file.");
    }
}</PRE>
<P>As you can see, the structure of the program is very similar to the ones we have 
	seen in the previous sections. The differences are:
</P>
<UL>
	<LI>
		The call to <CODE>device.PcapDumpOpen( capFile )</CODE>
	is issued once the interface is opened. This call opens a dump file and 
	associates it with the interface.
	<LI>
		The packets are written to this file with the <CODE>device.PcapDump( packet )</CODE>
		call in the packet handler. Note the use of the sender object parameter passed 
		to the packet handler callback which is casted to a <CODE>PcapDevice</CODE>.
	</LI>
</UL>
<B>Reading packets from a dump file</B>
<P>Now that we have a dump file available, we can try to read its content. The 
	following code opens a WinPcap/libpcap dump file and displays every packet 
	contained in the file. The <CODE>SharpPcap.GetPcapOfflineDevice( capFile )</CODE>
	function returns a <CODE>PcapDevice</CODE> object which represents the offline 
	capture file that we read, then the usual PcapOnPacketArrival event is used to 
	sequence through the packets. As you can see, reading packets from an offline 
	capture is nearly identical to receiving them from a physical interface.
</P>
<PRE>Console.Write("-- Please enter an input capture file name: ");
string capFile = Console.ReadLine();

PcapDevice device;

try
{
    //Get an offline file pcap device
    device = SharpPcap.Pcap.GetPcapOfflineDevice( capFile );
    //Open the device for capturing
    device.PcapOpen();
} 
catch(Exception e)
{
    Console.WriteLine(e.Message);
    return;
}

//Register our handler function to the 'packet arrival' event
device.PcapOnPacketArrival += 
    new SharpPcap.PacketArrivalEvent( device_PcapOnPacketArrival );

Console.WriteLine();
Console.WriteLine
    ("-- Capturing from '{0}', hit 'Ctrl-C' to exit...",
    capFile);

//Start capture 'INFINTE' number of packets
//This method will return when EOF reached.
device.PcapCapture( SharpPcap.INFINITE );

//Close the pcap device
device.PcapClose();
Console.WriteLine("-- End of file reached.");</PRE>
<P></P>
<H3 id="sendPackets">7. Sending Packets</H3>
<P>One of the coolest things about WinPcap compared to libpcap is its ability to 
	send raw packets out to the network.</P>
<P><B>Sending a single packet with SharpPcap</B></P>
<P>The simplest way to send a packet is shown in the following code snippet. After 
	opening an adapter, <CODE>PcapSendPacket</CODE> is called to send a 
	hand-crafted packet. <CODE>PcapSendPacket</CODE> takes as arguments a byte 
	array or a <CODE>Packet</CODE> object containing the data to send. Notice that 
	the buffer is sent to the net as is, without any manipulation. This means that 
	the application has to create the correct protocol headers in order to send 
	something meaningful.</P>
<PRE>//Open the device
device.PcapOpen();

//Generate a random packet
byte[] bytes = GetRandomPacket();

try
{
    //Send the packet out the network device
    device.PcapSendPacket( bytes );
    Console.WriteLine("-- Packet sent successfuly.");
}
catch(Exception e)
{
    Console.WriteLine("-- "+ e.Message );
}

//Close the pcap device
device.PcapClose();
Console.WriteLine("-- Device closed.");</PRE>
<P><B>Send queues</B>
</P>
<P>While <CODE>PcapSendPacket</CODE> offers a simple and immediate way to send a 
	single packet, <B>send queues </B>provides an advanced, powerful and optimized 
	mechanism to send a collection of packets. A send queue is a container for a 
	variable number of packets that will be sent to the network. It has a size, 
	that represents the maximum amount of bytes it can store.
</P>
<P>SharpPcap represents a send queue using the <CODE>PcapSendQueue</CODE> class 
	which is constructed specifying the size of the new send queue.
</P>
<P>Once the send queue is created, <CODE>PcapSendQueue.Add()</CODE> can be called 
	to add a packet to the send queue. This function takes a <CODE>PcapHeader</CODE>
	with the packet's timestamp and length and a buffer or a <CODE>Packet</CODE> object 
	holding the data of the packet. These parameters are the same as those received 
	by the <CODE>OnPacketArrival</CODE> event, therefore queuing a packet that was 
	just captured or read from a file is a matter of passing these parameters to <CODE>PcapSendQueue.Add()</CODE>.
</P>
<P>To transmit a send queue, SharpPcap provides the <CODE>PcapDevice.PcapSendQueue(PcapSendQueue 
		q, bool sync)</CODE> function. Note the second parameter: if true, the send 
	will be <EM>synchronized</EM>, i.e. the relative timestamps of the packets will 
	be respected. This operation requires a remarkable amount of CPU, because the 
	synchronization takes place in the kernel driver using "busy wait" loops. 
	Although this operation is quite CPU intensive, it often results in very high 
	precision packet transmissions (often around few microseconds or less).
</P>
<P>Note that transmitting a send queue with <CODE>PcapDevice.PcapSendQueue() </CODE>
	is much more efficient than performing a series of <CODE>PcapDevice.PcapSendPacket()</CODE>, 
	since the send queue is buffered at kernel level drastically decreasing the 
	number of context switches.
</P>
<P>When a queue is no longer needed, it can be deleted with <CODE>PcapSendQueue.Dispose()</CODE>
	that frees all the buffers associated with the send queue.
</P>
<P>The next program shows how to use send queues. It opens a capture file with <CODE>SharpPcap.GetOfflineDevice()</CODE>, 
	then it stores the packets from the file to a properly allocated send queue. At 
	his point it transmits the queue synchronized.</P>
<P>Note that the link-layer of the dumpfile is compared with the one of the 
	interface that will send the packets using <CODE>PcapDevice.DataLink</CODE> property, 
	and a warning is printed if they are different -- it is important that the 
	capture-file link-layer be the same as the adapter's link layer for otherwise 
	the transmission is pointless.</P>
<PRE>PcapDevice device;

try
{
    //Get an offline file pcap device
    device = SharpPcap.Pcap.GetPcapOfflineDevice( capFile );
    //Open the device for capturing
    device.PcapOpen();
} 
catch(Exception e)
{
    Console.WriteLine(e.Message);
    return;
}

Console.Write("Queueing packets...");

//Allocate a new send queue
PcapSendQueue squeue = new PcapSendQueue
    ( (int)((PcapOfflineDevice)device).PcapFileSize );
Packet packet;

try
{
    //Go through all packets in the file and add to the queue
    while( (packet=device.PcapGetNextPacket()) != null )
    {
        if( !squeue.Add( packet ) )
        {
            Console.WriteLine("Warning: packet buffer too small, "+
                "not all the packets will be sent.");
            break;
        }
    }
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
    return;
}

Console.WriteLine("OK");

Console.WriteLine();
Console.WriteLine("The following devices are available on this machine:");
Console.WriteLine("----------------------------------------------------");
Console.WriteLine();

int i=0;

List<PcapDevice> devices = SharpPcap.GetAllDevices();
/* Scan the list printing every entry */
foreach(PcapDevice dev in devices)
{
    /* Description */
    Console.WriteLine("{0}) {1}",i,dev.PcapDescription);
    i++;
}

Console.WriteLine();
Console.Write("-- Please choose a device to transmit on: ");
i = int.Parse( Console.ReadLine() );
devices[i].PcapOpen();
string resp;

if(devices[i].PcapDataLink != device.PcapDataLink)
{
    Console.Write("Warning: the datalink of the capture"+
        " differs from the one of the selected interface, continue? [YES|no]");
    resp = Console.ReadLine().ToLower();

    if((resp!="")&amp;&amp;( !resp.StartsWith("y")))
    {
        Console.WriteLine("Cancelled by user!");
        devices[i].PcapClose();
        return;
    }
}
device.PcapClose();
device = devices[i];

Console.Write("This will transmit all queued packets through"+
    " this device, continue? [YES|no]");
resp = Console.ReadLine().ToLower();

if((resp!="")&amp;&amp;( !resp.StartsWith("y")))
{
    Console.WriteLine("Cancelled by user!");
    return;
}

try
{
    Console.Write("Sending packets...");
    int sent = device.PcapSendQueue( squeue, true );
    Console.WriteLine("Done!");
    if( sent &lt; squeue.CurrentLength )
    {
        Console.WriteLine("An error occurred sending the packets: {0}. "+
            "Only {1} bytes were sent\n", device.PcapLastError, sent);
    }
}
catch(Exception e)
{
    Console.WriteLine( "Error: "+e.Message );
}
//Free the queue
squeue.Dispose();
Console.WriteLine("-- Queue is disposed.");
//Close the pcap device
device.PcapClose();
Console.WriteLine("-- Device closed.");</PRE>
<H3 id="statistics">8. Gathering Statistics on the network traffic</H3>
<P>This section shows another advanced feature of WinPcap: the ability to collect 
	statistics about network traffic. WinPcap's statistical engine makes use of the 
	kernel-level packet filter to efficiently classify the incoming packet. You can 
	take a look at the <A class="el" href="http://www.winpcap.org/docs/docs31/html/group__NPF.html">
		NPF driver internals manual</A> if you want to learn more details.
</P>
<P>In order to use this feature, the programmer must open an adapter and put it in <EM>statistical</EM>
	<EM>mode</EM>. This can be done by setting the <CODE>PcapDevice.PcapMode</CODE> 
	property. In particular, <CODE>PcapMode.Statistics</CODE> must be used as the <EM>mode</EM>
	argument of this property.
</P>
<P>With statistical mode, making an application that monitors the TCP traffic load 
	is a matter of few lines of code. The following sample shows how to do it.</P>
<PRE>//Register our handler function to the 'pcap statistics' event
device.PcapOnPcapStatistics += 
    new SharpPcap.Pcap.PcapStatisticsEvent( device_PcapOnPcapStatistics );

//Open the device for capturing
//true -- means promiscuous mode
//1000 -- means stats will be collected 1000ms
device.PcapOpen(true, 1000);

//Handle TCP packets only
device.PcapSetFilter( "tcp" );
            
//Set device to statistics mode
device.PcapMode = PcapMode.Statistics;

Console.WriteLine();
Console.WriteLine("-- Gathering statistics on \"{0}\", hit 'Enter' to stop...",
    device.PcapDescription);

//Start the capturing process
device.PcapStartCapture();

//Wait for 'Enter' from the user.
Console.ReadLine();

//Stop the capturing process
device.PcapStopCapture();

//Close the pcap device
device.PcapClose();
Console.WriteLine("Capture stopped, device closed.");</PRE>
<P>And our event handler will print the statistics:</P>
<PRE>static int oldSec=0;
static int oldUsec=0;
/// &lt;SUMMARY&gt;
/// Gets a pcap stat object and calculate bps and pps
/// &lt;/SUMMARY&gt;
private static void device_PcapOnPcapStatistics(object sender, PcapStatistics statistics)
{
    /* Calculate the delay in microseconds from the last sample. */
    /* This value is obtained from the timestamp that's associated with the sample. */
    int delay=(statistics.Seconds - oldSec) * 1000000 - oldUsec + statistics.MicroSeconds;
    /* Get the number of Bits per second */
    long bps =  ( statistics.RecievedBytes * 8 * 1000000) / delay;
    /*                  		     ^        ^
                        		     |        |
                        		     |        |
                        		     |        |
            converts bytes in bits      -----         |
          delay is expressed in microseconds ---------
    */

    /* Get the number of Packets per second */
    long pps=(statistics.RecievedPackets * 1000000) / delay;

    /* Convert the timestamp to readable format */
    string ts = statistics.Date.ToLongTimeString();

    /* Print Statistics */
    Console.WriteLine("{0}: bps={1}, pps={2}", ts, bps, pps); 

    //store current timestamp
    oldSec=statistics.Seconds;
    oldUsec=statistics.MicroSeconds;
}</PRE>
<P>Note that this example is by far more efficient than a program that captures the 
	packets in the traditional way and calculates statistics at user-level. 
	Statistical mode requires the minimum amount of data copies and context 
	switches and therefore the CPU is optimized. Moreover, a very small amount of 
	memory is required.</P>

<hr>
	
<H4>References</H4>
<UL>
	<LI>
		<A href="http://sharppcap.sourceforge.net">SharpPcap</A>
	- the homepage of the SharpPcap library.
	<LI>
		<A href="http://www.winpcap.org/">WinPcap</A>
	- a packet capture framework for Windows.
	<LI>
		<A href="http://jpcap.sourceforge.net/">JPcap</A> - A Java wrapper for libpcap 
		and WinPcap. All the packet parser classes of SharpPcap were translated from 
		JPcap.
	</LI>
</UL>
